package {{package}};

{{#imports}}
import {{import}};
{{/imports}}
import io.micronaut.test.extensions.junit5.annotation.MicronautTest;
import io.micronaut.http.client.HttpClient;
import io.micronaut.http.client.annotation.Client;
import io.micronaut.runtime.server.EmbeddedServer;
import io.micronaut.http.HttpStatus;
import io.micronaut.http.MutableHttpRequest;
import io.micronaut.http.HttpRequest;
import io.micronaut.http.HttpResponse;
import io.micronaut.http.MediaType;
import io.micronaut.http.uri.UriTemplate;
import io.micronaut.http.cookie.Cookie;
import io.micronaut.http.client.multipart.MultipartBody;
import io.micronaut.core.type.Argument;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Assertions;
import jakarta.inject.Inject;
{{#reactive}}
import reactor.core.publisher.Mono;
{{/reactive}}
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.HashSet;


/**
 * API tests for {{classname}}
 */
@MicronautTest
public class {{classname}}Test {

    @Inject
    EmbeddedServer server;

    @Inject
    @Client
    HttpClient client;

    @Inject
    {{classname}} controller;

    {{#operations}}
    {{#operation}}
    /**
     * This test is used to validate the implementation of {{operationId}}() method
     *
     * The method should: {{summary}}
     {{#notes}}
     *
     * {{notes}}
     {{/notes}}
     *
     * TODO fill in the parameters and test return value.
     */
    @Test
        {{^generateControllerFromExamples}}
    @Disabled("Not Implemented")
        {{/generateControllerFromExamples}}
    void {{operationId}}MethodTest() {
        // given
        {{#allParams}}
        {{{dataType}}} {{paramName}} = {{{example}}};
        {{/allParams}}

        // when
        {{#returnType}}{{{returnType}}} result = {{/returnType}}controller.{{operationId}}({{#allParams}}{{paramName}}{{^-last}}, {{/-last}}{{/allParams}}){{#reactive}}.block(){{/reactive}}{{#wrapInHttpResponse}}.body(){{/wrapInHttpResponse}};

        // then
        {{^generateControllerFromExamples}}
        Assertions.assertTrue(true);
        {{/generateControllerFromExamples}}
        {{#generateControllerFromExamples}}
            {{#returnType}}
                {{#vendorExtensions.example}}
        Assertions.assertEquals(result, {{{vendorExtensions.example}}});
                {{/vendorExtensions.example}}
            {{/returnType}}
        {{/generateControllerFromExamples}}
    }

    /**
     * This test is used to check that the api available to client through
     * '{{{path}}}' to the features of {{operationId}}() works as desired.
     *
     * TODO fill in the request parameters and test response.
     */
    @Test
        {{^generateControllerFromExamples}}
    @Disabled("Not Implemented")
        {{/generateControllerFromExamples}}
    void {{operationId}}ClientApiTest() throws IOException {
        // given
        {{!Create the body}}
        {{#bodyParam}}
        {{{dataType}}} body = {{{example}}};
        {{/bodyParam}}
        {{#formParams.0}}
        Map<String, Object> form = new HashMap<String, Object>(){{openbrace}}{{openbrace}}
            // Fill in the body form parameters
            {{#formParams}}
                {{^isFile}}
            put("{{{baseName}}}", {{{example}}});
                {{/isFile}}
                {{#isFile}}
            put("{{{baseName}}}", new FileReader(File.createTempFile("test", ".tmp")));
                {{/isFile}}
            {{/formParams}}
        {{closebrace}}{{closebrace}};
        {{/formParams.0}}
        {{#isMultipart}}
            {{^formParams}}
        MultipartBody body = MultipartBody.builder() // Create multipart body
                {{#bodyParams}}
                    {{^isFile}}
            .addPart("{{{baseName}}}", {{^isString}}String.valueOf({{/isString}}{{{example}}}{{^isString}}){{/isString}})
                    {{/isFile}}
                    {{#isFile}}
                        {{#contentType}}
            .addPart("{{{baseName}}}", "filename", MediaType.of("{{{contentType}}}"), File.createTempFile("test", ".tmp"))
                        {{/contentType}}
                        {{^contentType}}
            .addPart("{{{baseName}}}", "filename", File.createTempFile("test", ".tmp"))
                        {{/contentType}}
                    {{/isFile}}
                {{/bodyParams}}
            .build();
            {{/formParams}}
        {{/isMultipart}}
        {{!Create the uri with path variables}}
        String uri = UriTemplate.of("{{{path}}}").expand(new HashMap{{^pathParams}}<>(){{/pathParams}}{{#pathParams.0}}<String, Object>(){{openbrace}}{{openbrace}}
            // Fill in the path variables
        {{#pathParams}}
            put("{{{baseName}}}", {{{example}}});
        {{/pathParams}}
        {{closebrace}}{{closebrace}}{{/pathParams.0}});
        {{!Create the request with body and uri}}
        MutableHttpRequest<?> request = HttpRequest.{{httpMethod}}{{#vendorExtensions.methodAllowsBody}}{{#bodyParam}}(uri, body){{/bodyParam}}{{#isMultipart}}{{^formParams}}(uri, body){{/formParams}}{{/isMultipart}}{{#formParams.0}}(uri, form){{/formParams.0}}{{^bodyParam}}{{^isMultipart}}{{^formParams}}(uri, null){{/formParams}}{{/isMultipart}}{{/bodyParam}}{{/vendorExtensions.methodAllowsBody}}{{^vendorExtensions.methodAllowsBody}}(uri){{/vendorExtensions.methodAllowsBody}}{{!Fill in all the request parameters}}{{#vendorExtensions.x-contentType}}
            .contentType("{{{vendorExtensions.x-contentType}}}"){{/vendorExtensions.x-contentType}}{{#vendorExtensions.x-accepts}}
            .accept("{{{vendorExtensions.x-accepts}}}"){{/vendorExtensions.x-accepts}}{{#headerParams}}
            .header("{{{baseName}}}", {{^isString}}String.valueOf({{/isString}}{{{example}}}{{^isString}}){{/isString}}){{/headerParams}}{{#cookieParams}}
            .cookie(Cookie.of("{{{baseName}}}", {{{example}}})){{/cookieParams}};
        {{!Fill in the query parameters}}
        {{#queryParams.0}}
        request.getParameters()
            {{#queryParams}}
                {{#isCollectionFormatMulti}}
            .add("{{{baseName}}}", {{{example}}}){{#-last}};{{/-last}} // The query format should be multi
                {{/isCollectionFormatMulti}}
                {{#isDeepObject}}
            .add("{{{baseName}}}[property]", "value"){{#-last}};{{/-last}} // The query format should be deep-object
                {{/isDeepObject}}
                {{^isCollectionFormatMulti}}
                    {{^isDeepObject}}
            .add("{{{baseName}}}", {{^isString}}String.valueOf({{/isString}}{{{example}}}{{^isString}}){{/isString}}){{#-last}};{{/-last}} // The query parameter format should be {{collectionFormat}}
                    {{/isDeepObject}}
                {{/isCollectionFormatMulti}}
            {{/queryParams}}
        {{/queryParams.0}}

        // when
        HttpResponse<?> response = client.toBlocking().exchange(request{{#returnType}}, {{#returnContainer}}Argument.of({{#isArray}}List{{/isArray}}{{#isMap}}Map{{/isMap}}.class, {{#isMap}}String.class, {{/isMap}}{{{returnBaseType}}}.class){{/returnContainer}}{{^returnContainer}}{{{returnType}}}.class{{/returnContainer}}{{/returnType}});{{^returnType}} // To retrieve body you must specify required type (e.g. Map.class) as second argument {{/returnType}}

        // then
        Assertions.assertEquals(HttpStatus.OK, response.status());
        {{#generateControllerFromExamples}}
            {{#returnType}}
        Assertions.assertEquals(response.body(), {{{vendorExtensions.example}}});
            {{/returnType}}
        {{/generateControllerFromExamples}}
    }

    {{/operation}}
    {{/operations}}
}
